package nachos.threads;
import nachos.ag.BoatGrader;

public class Boat
{
    static BoatGrader bg;
    
    public static void selfTest()
    {
	BoatGrader b = new BoatGrader();
	
	System.out.println("\n ***Testing Boats with only 2 children***");
	begin(2, 3, b);

//	System.out.println("\n ***Testing Boats with 2 children, 1 adult***");
//  	begin(1, 2, b);

//  	System.out.println("\n ***Testing Boats with 3 children, 3 adults***");
//  	begin(3, 3, b);
    }

    private static Lock start = new Lock();
    private static Semaphore passenger = new Semaphore(1);
    private static Semaphore captain = new Semaphore(1);
    //this variable can take as values n(nobody), a(adult) and c(child)
    private static char passengerIs = 'n';
    private static char captainIs = 'n';
    private static Integer people;
    private static Integer peopleInMolokai=0;

    public static void begin( int adults, int children, BoatGrader b )
    {
	// Store the externally generated autograder in a class
	// variable to be accessible by children.
        bg = b;

	// Instantiate global variables here
	
	// Create threads here. See section 3.4 of the Nachos for Java
	// Walkthrough linked from the projects page.
        /*
	Runnable r = new Runnable() {
	    public void run() {
                SampleItinerary();
            }
        };
        KThread t = new KThread(r);
        t.setName("Sample Boat Thread");
        t.fork();*/
        people = adults + children;
        Runnable a = new Runnable(){
            public void run(){
                AdultItinerary();
            }
        };
        Runnable c = new Runnable(){
            public void run(){
                ChildItinerary();
            }
        };

        KThread[] tc = new KThread[children];
        for(int i = 0; i < children; i++){
            tc[i]= new KThread(c);
            tc[i].setName("Child Thread");
            tc[i].fork();
        }

        KThread[] ta = new KThread[adults];
        for(int i = 0; i < adults; i++){
            ta[i]= new KThread(a);
            ta[i].setName("Adult Thread");
            ta[i].fork();
        }

    }

    static void AdultItinerary()
    {
	/* This is where you should put your solutions. Make calls
	   to the BoatGrader to show that it is synchronized. For
	   example:
	       bg.AdultRowToMolokai();
	   indicates that an adult has rowed the boat across to Molokai
	*/
        passenger.P();
        passengerIs='a';
        bg.AdultRideToMolokai();
        peopleInMolokai++;
        passengerIs='n';
        passenger.V();
        System.out.println("Adult left the boat");
    }

    static void ChildItinerary()
    {
        
        passenger.P();
        passengerIs = 'c';
        if(captainIs == 'c')
            bg.ChildRideToMolokai();
        captain.P();
        if(captainIs == 'c' && !(peopleInMolokai==people-1)){
            System.out.println("Switch captain");
            bg.ChildRowToOahu();
        }
        captainIs = 'c';
        passenger.V();
        while(true){
            bg.ChildRowToMolokai();
            if((passengerIs=='c' || peopleInMolokai==people-1))
                break;
            bg.ChildRowToOahu();
        }
        peopleInMolokai++;
        captain.V();
        System.out.println("Child left the boat");
    }

    static void SampleItinerary()
    {
	// Please note that this isn't a valid solution (you can't fit
	// all of them on the boat). Please also note that you may not
	// have a single thread calculate a solution and then just play
	// it back at the autograder -- you will be caught.
	System.out.println("\n ***Everyone piles on the boat and goes to Molokai***");
	bg.AdultRowToMolokai();
	bg.ChildRideToMolokai();
	bg.AdultRideToMolokai();
	bg.ChildRideToMolokai();
    }
    
}
